<template>
  <div class="validate-input-container pb-3">
    <!--    v-model="inputRef.val" :value="inputRef.val"-->
    <input
      v-if="tag !== 'textarea'"
      type="text"
      class="form-control"
      :class="{ 'is-invalid': inputRef.error }"
      :value="inputRef.val"
      @blur="validateInput"
      @input="updateValue"
      v-bind="$attrs"
    />
    <textarea
      v-else
      class="form-control"
      :class="{ 'is-invalid': inputRef.error }"
      :value="inputRef.val"
      @blur="validateInput"
      @input="updateValue"
      v-bind="$attrs"
    ></textarea>
    <span class="invalid-feedback" v-if="inputRef.error">{{
      inputRef.message
    }}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, PropType, onMounted, watch, computed } from "vue";
import { emitter } from "@/components/VaildateForm.vue";

const emailReg =
  /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;

interface RuleProp {
  //input 里的type属性required属于必填项 email检测是不是邮箱
  type: "required" | "email" | "custom", //他可以同时实现两种， 必填的 | type:'email'
  message: string;
  validator?: () => boolean;
}

//RulesProp 是在 RuleProp 基础上拓展的
export type RulesProp = RuleProp[];
// 将添加到父元素身上的属性放到子元素上，只需要做两件事
// 一：把父元素的东西删除 inheritAttrs:false
// 二：使用 v-bind="$attrs"绑定上元素
// inheritAttrs:false
export type TagType = "input" | "textarea";
export default defineComponent({
  props: {
    //我们在上面已经定义了它是一个数组所以不需要加[]
    rules: Array as PropType<RulesProp>,
    modelValue: String,
    tag: {
      type: String as PropType<TagType>,
    },
    // modelValue:'modelValue'
  },
  setup(props, context) {
    console.log(props);
    const inputRef = reactive({
      // 如果它一开始有值的话，应该在你的modelValue取值
      //如果刷新页面你的input里面有值是不是要在页面显示出来，显示出来的就是你的props.modelValue
      val: props.modelValue || "", //内容 他应该是有这两种情况的
      // val:computed({
      //   get() => props.modelValue || "",
      //   set:(val)=>{
      //     context.emit('update:modeValue',val)
      //   }
      // }),
      error: false, //返回一个错误信息
      message: "", //返回的错误信息
    })
    //你往里面输入内容鼠标只起到了一个失焦和获焦的作用
    // 你输入内容应该是你的键盘事件
    const updateValue = (e: KeyboardEvent) => {
      //HTMLInputElement 是input标签的这个元素
      // 就是拿到你的数据源推断他是不是当前的元素，然后取到value的值赋给targetValue
      const targetValue = (e.target as HTMLInputElement).value;
      inputRef.val = targetValue;
      // 子组件可以使用 $emit,让父组件监听到自定义事件
      context.emit("value", targetValue);
    };
    watch(()=>props.modelValue,(newValue)=>{
      inputRef.val= newValue || ''
    })
    const validateInput = () => {
      if (props.rules) {
        const allPassed = props.rules.every((rule) => {
          //检测数组中的元素是否通过检测
          let passed = true;
          inputRef.message = rule.message;
          switch (rule.type) {
            case "required":
              //不能为空才可以通过
              passed = inputRef.val.trim() !== "";
              break;
            case "email":
              // 检测你输入框里的内容
              passed = emailReg.test(inputRef.val);
              break;
            // 重复密码判断
            case 'custom':
              passed = rule.validator ? rule.validator() : true
              break;
            default: //如果以上都不符合
              break;
          }
          // 把最后的结果返回出去
          return passed;
        });
        inputRef.error = !allPassed;
        return allPassed;
      }
    };
    onMounted(() => {
      // 去执行你绑定的那个事件
      // emitter.emit('form-item-created',inputRef.val)
      emitter.emit("form-item-created", validateInput);
    });
    return {
      inputRef,
      validateInput,
      updateValue,
    };
  },
});
</script>

<style></style>
